package com.ytkj.digitalConstruction.service.message;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ytkj.digitalConstruction.dao.base.ConfigMapper;
import com.ytkj.digitalConstruction.dao.message.MessageMapper;
import com.ytkj.digitalConstruction.dao.message.MessageUserMapper;
import com.ytkj.digitalConstruction.entity.base.Config;
import com.ytkj.digitalConstruction.entity.message.Message;
import com.ytkj.digitalConstruction.entity.message.MessageUser;
import com.ytkj.digitalConstruction.entity.user.User;
import com.ytkj.digitalConstruction.enums.exception.ExceptionMsgEnum;
import com.ytkj.digitalConstruction.enums.message.MessageStatusEnum;
import com.ytkj.digitalConstruction.enums.message.MessageUserStatusEnum;
import com.ytkj.digitalConstruction.exception.CustomException;
import com.ytkj.digitalConstruction.httpbean.PageParam;
import com.ytkj.digitalConstruction.httpbean.message.reqbean.BaseMqBean;
import com.ytkj.digitalConstruction.httpbean.message.reqbean.FileMessageMqBean;
import com.ytkj.digitalConstruction.httpbean.message.reqbean.MqMessageDetails;
import com.ytkj.digitalConstruction.httpbean.message.reqbean.TextMessageMqBean;
import com.ytkj.digitalConstruction.httpbean.message.resbean.MessageDetails;
import com.ytkj.digitalConstruction.httpbean.message.resbean.ResMessage;
import com.ytkj.digitalConstruction.rabbit.BaseVar;
import com.ytkj.digitalConstruction.rabbit.Sender;
import com.ytkj.digitalConstruction.threads.MyThreadFactory;

/**
 * Message类的业务处理类
 * 
 * @author momei
 */
@Service
public class MessageService {

	Logger log = LoggerFactory.getLogger(getClass());

	@Autowired
	private MessageMapper messageMapper;
	@Autowired
	private ConfigMapper configMapper;
	@Autowired
	private BaseVar rabbitBaseVar;
	@Autowired
	private Sender sender;

	@Autowired
	private MessageUserMapper messageUserMapper;

	private static Map<Integer, ScheduledFuture<?>> scheduledMap = new HashMap<Integer, ScheduledFuture<?>>();

	/**
	 * 新增消息
	 * 
	 * @param message
	 *            消息对象
	 * @param userIdList
	 *            消息接收人id list
	 * @param request 
	 * @return 结果码 null或 0
	 * @throws Exception
	 */
	@Transactional
	public Integer insert(Message message, List<Integer> userIdList, User currentUser){
		Integer resCode = null;
		// 对参数进行处理
		message.setCreateDate(new Date());
		message.setPublisher(currentUser.getUserId());
		// 未发送
		message.setStatus(MessageStatusEnum.UNSEND.getValue());

		int num = messageMapper.insertSelective(message);
		// 添加成功
		if (num > 0) {
			// 添加message-user
			for (int i = 0; i < userIdList.size(); i++) {
				MessageUser user = new MessageUser();
				user.setMessageId(message.getMessageId());
				user.setUserId(userIdList.get(i));
				// 未发送
				user.setStatus(MessageUserStatusEnum.UNSEND.getValue());
				messageUserMapper.insertSelective(user);
			}

			// 将任务发送到MQ
			String msgType = message.getMsgType() == null?"text":message.getMsgType();
			messageTimer(message, StringUtils.arrayToDelimitedString(userIdList.toArray(), ","), msgType);
			resCode = 1;
		}
		return resCode;
	}

	/**
	 * @param message
	 *            消息对象
	 * @param userIdsStr
	 *            接收人ids
	 * @param type 
	 * 			发送的消息类型
	 * @throws Exception
	 * 
	 */
	private void messageTimer(Message message, String userIdsStr, String type){

		if (message == null || StringUtils.isEmpty(userIdsStr) || type.isEmpty()) {
			throw new CustomException(ExceptionMsgEnum.PARAM_INVALID);
		}
		String msg = jsonMsgContent(message.getMessageId().toString(),message.getContent(),type,userIdsStr);
		if(msg == null){
			return;
		}
		// 发送消息
		ScheduledExecutorService ses = new ScheduledThreadPoolExecutor(10, new MyThreadFactory("sendMessage"));
		switch (message.getType()) {
			// 两个平台都发送
			case 0: {
				ScheduledFuture<?> sf1 = timmerTask(ses, msg, message, rabbitBaseVar.getRoutingkeyDingMessage());
				scheduledMap.put(message.getMessageId(), sf1);
	
				ScheduledFuture<?> sf2 = timmerTask(ses, msg, message, rabbitBaseVar.getRoutingkeyMessage());
				scheduledMap.put(message.getMessageId(), sf2);
	
				break;
			}
			// 钉钉消息
			case 1: {
				ScheduledFuture<?> sf1 = timmerTask(ses, msg, message, rabbitBaseVar.getRoutingkeyDingMessage());
				scheduledMap.put(message.getMessageId(), sf1);
				break;
			}
			// 平台消息
			case 2: {
				ScheduledFuture<?> sf2 = timmerTask(ses, msg, message, rabbitBaseVar.getRoutingkeyMessage());
				scheduledMap.put(message.getMessageId(), sf2);
				break;
			}
			default: {
				break;
			}

		}

	}
	
	/**
	 * 发送流程消息 
	 * 
	 * @param message 消息对象
	 * @return 消息接收方返回的 Json格式字符串,若必要参数为空时，返回null
	 */
	public String  sendProcessMsg(Message message,String userIdsStr){
		if (message == null || StringUtils.isEmpty(userIdsStr)) {
			log.error("MessageService sendProcessMsg Exception: Parameter illegality");
			return null;
		}
		String msg = jsonMsgContent("",message.getContent(),message.getMsgType(),userIdsStr);
		if(msg == null){
			return null;
		}
		
		//只给钉钉发送
		String response = sender.send(msg, rabbitBaseVar.getRoutingkeyDingMessage());
		return response;
	}

	/**
	 * 将消息转换为json格式的字符串
	 * 
	 * @param msgId 
	 * 			消息id(可为空字符串)
	 * @param content
	 * 			消息内容
	 * @param type
	 * 			消息类型
	 * @param userIdsStr
	 * 			以逗号间隔的接收人id list 如： "1,2,3"
	 * @return 如果参数异常时返回null,否则返回Json格式的字符串
	 * @throws Exception 
	 */
	private String jsonMsgContent(String msgId, String content, String type,String userIdsStr){
		if(msgId == null) {
			throw new CustomException(ExceptionMsgEnum.PARAM_INVALID);
		}
		if(StringUtils.isEmpty(type) || StringUtils.isEmpty(userIdsStr) || StringUtils.isEmpty(content)){
			log.error("MessageService jsonMsgContent Exception: Parameter is null!");
			throw new CustomException(ExceptionMsgEnum.PARAM_INVALID);
		}
		BaseMqBean mqBean = null;
		switch(type){
			case "text": {
				TextMessageMqBean textMessage = new TextMessageMqBean();
				textMessage.setContent(content);
				mqBean = textMessage;

				break;
			}
			case "file": {
				FileMessageMqBean filelMessage = new FileMessageMqBean();
				filelMessage.setFilePath(content);
				mqBean = filelMessage;
				break;
				
			}
			case "link": {
				TextMessageMqBean textMessage = new TextMessageMqBean();
				textMessage.setContent(content);
				mqBean = textMessage;
				break;
			}
			default: {
				break;
			}
		}
		mqBean.setId(msgId);
		mqBean.setMsgType(type);
		mqBean.setUserIdList(userIdsStr);
		return JSON.toJSONString(mqBean);
	}

	/**
	 * @param ses
	 * @param msg
	 * @param message
	 * @param routingKey
	 * @return
	 */
	private ScheduledFuture<?> timmerTask(ScheduledExecutorService ses, String msg, Message message,
			String routingKey) {
		// 在消息的发布时间进行发布
		long delay = message.getPublicDate().getTime() - System.currentTimeMillis();
		delay = delay < 0 ? 0 : delay;
		ScheduledFuture<?> sf = ses.schedule(new TimerTask() {
			@Override
			public void run() {
				log.info("timer task running!");
				String response = sender.send(msg, routingKey);
				Integer sendMsgId = findSendMessageId(msg);
				updateMessagStatus(response,sendMsgId);
				scheduledMap.remove(message.getMessageId());
				log.info("timer task finished!");
			}
		}, delay, TimeUnit.MILLISECONDS);

		return sf;
	}
	
	/**
     * 修改某条消息用户的接受状态
     * 
     * @param response 消息发送成功后，接收方返回的JONSON格式的字符串
	 * @throws Exception 
     */
    @Transactional
	private void updateMessageUserStatus(String response,Integer sendMsgId){
		if(!JSONObject.parseObject(response).getBoolean("success")){
			log.error("Sender updateMessagStatus Exception: the response of MQ is false!");
			return;
		}
		if(sendMsgId == null){
			log.error("Sender updateMessageUserStatus Exception: Parameter is not valid!");
			return;
		}
		
		JSONObject sendResult = JSONObject.parseObject(response).getJSONObject("obj")
				.getJSONObject("dingtalk_corp_message_corpconversation_getsendresult_response")
				.getJSONObject("result")
				.getJSONObject("send_result");
		//未读
		JSONArray unreadUserIdList = sendResult.getJSONObject("unread_user_id_list").getJSONArray("string");
		String unreadUserIdListStr = "[]";
		if(unreadUserIdList != null){
			unreadUserIdListStr = unreadUserIdList.toString();
		}
		//已读
		JSONArray readUserIdList = sendResult.getJSONObject("read_user_id_list").getJSONArray("string");
		System.err.println("readUserIdList：" + readUserIdList);
		String readUserIdListStr = "[]";
		if(readUserIdList != null){
			readUserIdListStr = readUserIdList.toString();
		}
		//发送失败
		JSONArray invalidUserIdList = sendResult.getJSONObject("invalid_user_id_list").getJSONArray("string");
		System.err.println("readUserIdList：" + invalidUserIdList);
		String invalidUserIdListStr = "[]";
		if(invalidUserIdList != null){
			invalidUserIdListStr = invalidUserIdList.toString();
		}
		JSONArray failedUserIdList = sendResult.getJSONObject("failed_user_id_list").getJSONArray("string");
		String failedUserIdListStr = "[]";
		if(failedUserIdList != null){
			failedUserIdListStr = failedUserIdList.toString();
		}
		JSONObject forbiddenUserIdListObj =  sendResult.getJSONObject("forbidden_user_id_list");
		JSONArray forbiddenUserIdList = null;
		if(forbiddenUserIdListObj != null) {
			forbiddenUserIdList = forbiddenUserIdListObj.getJSONArray("string");
		}
		String forbiddenUserIdListStr = "[]";
		if(forbiddenUserIdList != null){
			forbiddenUserIdListStr = forbiddenUserIdList.toString();
		}

		//未读
		List<Integer> unreadUserIds = JSONArray.parseArray(unreadUserIdListStr, Integer.class);
		//已读
		List<Integer> readUserIds = JSONArray.parseArray(readUserIdListStr, Integer.class);
		//发送失败
		List<Integer> failedUserIds = JSONArray.parseArray(invalidUserIdListStr, Integer.class);
		failedUserIds.addAll(JSONArray.parseArray(failedUserIdListStr, Integer.class));
		failedUserIds.addAll(JSONArray.parseArray(forbiddenUserIdListStr, Integer.class));
		
		//未接受
		if(!unreadUserIds.isEmpty()){
			messageUserMapper.updateStatusByMessageIdAndUserIds(MessageUserStatusEnum.UNREAD.getValue(), sendMsgId, unreadUserIds);
		}
		if(!readUserIds.isEmpty()){
			//已接受
			messageUserMapper.updateStatusByMessageIdAndUserIds(MessageUserStatusEnum.READ.getValue(), sendMsgId, readUserIds);
		}
		if(!failedUserIds.isEmpty()){
			//发送失败
			messageUserMapper.updateStatusByMessageIdAndUserIds(MessageUserStatusEnum.FAILD.getValue(), sendMsgId, failedUserIds);
		}
		
		
	}

	/**
	 * 修改Message状态
	 * 
	 * @param response 消息接收方返回的JSON格式的字符串
	 * @throws Exception 
	 */
    @Transactional
	private void updateMessagStatus(String response,Integer sendMsgId){
		
    	JSONObject res = JSONObject.parseObject(response);
    	if(res == null || sendMsgId == null){
    		log.error("Sender updateMessageStatus Exception: Parameter is not valid!");
    		return;
    	}
       
		if(res.getBoolean("success") == false){ 
			log.error("Sender updateMessagStatus Exception: the response of MQ is false!");
			return;
		}

 		com.ytkj.digitalConstruction.entity.message.Message mes = messageMapper.selectByPrimaryKey(sendMsgId);
 		if(mes != null){
 			//已发送
 	 		mes.setStatus(MessageStatusEnum.SENT.getValue());
 	 		String taskId = res.getJSONObject("obj")
 	 				.getJSONObject("dingtalk_corp_message_corpconversation_asyncsend_response")
 	 				.getJSONObject("result").getString("task_id");
 	     	mes.setDingTaskId(taskId);
 	     	messageMapper.updateByPrimaryKeySelective(mes);	
 	     	//修改用户接受状态为未接收
 	     	messageUserMapper.updateStatusByMessageId(MessageUserStatusEnum.UNREAD.getValue(), sendMsgId);
 		}
 		
    }
	
	private Integer findSendMessageId(String msg) {
    	JSONObject message = JSONObject.parseObject(msg);
    	return  Integer.parseInt(message.getString("id"));		
	}

	/**
	 * 查询详情
	 * 
	 * @param id Message对象的messageId
	 * @return
	 */
	public List<MessageDetails> selectDetails(Integer id) {
		List<MessageDetails> detailsList = new ArrayList<MessageDetails>();
		Message message = messageMapper.selectByPrimaryKey(id);
		if (message == null) {
			return detailsList;
		}
		// 未读
		List<MessageUser> messageUserList = messageUserMapper.selectByMessageIdAndStatus(message.getMessageId(),
				MessageUserStatusEnum.UNREAD.getValue());
		if (!messageUserList.isEmpty()) {
			String response = sendMsgDetails(message.getMessageId(),message.getDingTaskId());
			updateMessageUserStatus(response,id);
		}
		detailsList = messageUserMapper.selectDetailsByMessageId(id);

		// 设置状态名
		updateMessageUserStatusName(detailsList);

		return detailsList;
	}
	
	/**
	 * 查询用户接受消息的的状态列表
	 * 
	 * @param dingTaskId
	 * 			钉钉的taskId
	 * @return 接收方返回的用户接受消息的状态列表
	 */
	public String sendMsgDetails(String dingTaskId) {
		return sendMsgDetails(null,dingTaskId);
	}

	/**
	 * 查询用户接受消息的的状态列表
	 * @param messageId 消息id
	 * @param dingTaskId 钉钉的taskId
	 * @return 接收方返回的用户接受消息的状态列表
	 */
	private String sendMsgDetails(Integer messageId, String dingTaskId) {
		MqMessageDetails mqDetails = new MqMessageDetails();
		mqDetails.setId(messageId);
		mqDetails.setTaskId(dingTaskId);
		String msg = JSON.toJSONString(mqDetails);
		String response = sender.send(msg, rabbitBaseVar.getRoutingkeyMessageDetails());
		return response;
	}

	/**
	 * 给状态添加名称
	 * 
	 * @param detailsList
	 */
	private void updateMessageUserStatusName(List<MessageDetails> detailsList) {

		for (MessageDetails details : detailsList) {
			Config config = configMapper.selectByPrimaryKey(details.getStatus());
			if (config != null) {
				details.setStatusName(config.getValue());
			}
		}
	}

	/**
	 * 
	 * @Title: deleteMessage @Description: 删除消息 @param messageId @return @throws
	 */
	@Transactional
	public Integer deleteMessage(Integer messageId) {
		ScheduledFuture<?> sf = scheduledMap.get(messageId);
		if (sf != null) {
			sf.cancel(true);
			scheduledMap.remove(messageId);
		}
		return messageMapper.updateByPrimaryKey(messageId);
	}

	/**
	 * 
	 * @Title: selectAll @Description: 查询所有未删除的消息 @return Integer @throws
	 */
	public List<Message> selectAll() {

		return messageMapper.selectAll();
	}
	
	/**
	 * @Title: select @Description: 按分页查询未删除消息 @param pageParam @return @throws
	 */
	public Page<ResMessage> select(PageParam pageParam,Integer userId) {
		PageHelper.startPage(pageParam.getPageCurrent(), pageParam.getPageSize());
		return messageMapper.selectByPublisher(userId);
	}

}
